package scriptshelper

import (
	"context"
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	kerrors "k8s.io/apimachinery/pkg/util/errors"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/constant"
	labelhelper "gopkg.openfuyao.cn/cluster-api-provider-bke/utils/label"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/log"
)

func CreateScriptsConfigMaps(c client.Client) error {

	scripts := map[string]string{}

	err := filepath.Walk(constant.K8sScriptsDir, func(path string, info os.FileInfo, err error) error {
		// skip dir
		if info.IsDir() {
			return nil
		}
		// only yaml file
		if strings.HasSuffix(path, ".sh") {
			scripts[info.Name()] = path
		}
		if strings.HasSuffix(path, ".py") {
			scripts[info.Name()] = path
		}
		return nil
	})

	if err != nil {
		return err
	}
	errs := []error{}

	for name, path := range scripts {
		cm := &corev1.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{
				Name:      name,
				Namespace: "cluster-system",
				Labels:    map[string]string{labelhelper.ScriptsLabelKey: ""},
			},
			Data: map[string]string{},
		}
		content, err := os.ReadFile(path)
		if err != nil {
			errs = append(errs, errors.Errorf("read file %s failed: %v", path, err))
			continue
		}

		// docToUnix
		content = []byte(strings.ReplaceAll(string(content), "\r\n", "\n"))

		cm.Data[name] = string(content)
		if err := c.Create(context.Background(), cm); err != nil {
			if apierrors.IsAlreadyExists(err) {
				if err := c.Update(context.Background(), cm); err != nil {
					err = errors.Errorf("update configmap %s failed: %v", name, err)
					errs = append(errs, err)
				}
				log.Infof("脚本已存在，更新环境初始化自定义脚本 %q 到 configmap %q", name, utils.ClientObjNS(cm))
				continue
			}
			err = errors.Errorf("create configmap %s failed: %v", name, err)
			errs = append(errs, err)
			continue
		}
		log.Infof("加载环境初始化自定义脚本 %q 到 configmap %q", name, utils.ClientObjNS(cm))
	}
	return kerrors.NewAggregate(errs)
}

func ListScriptsConfigMaps(c client.Client) ([]string, error) {
	cmList := &corev1.ConfigMapList{}
	err := c.List(context.Background(), cmList, &client.ListOptions{
		Namespace: "cluster-system",
		LabelSelector: labels.SelectorFromSet(
			map[string]string{labelhelper.ScriptsLabelKey: ""},
		),
	})
	if err != nil {
		return nil, err
	}

	var names []string
	for _, cm := range cmList.Items {
		names = append(names, cm.Name)
	}
	return names, nil
}
